package com.ruoyi.system.service.impl.wechat;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.wechat.WechatConstants;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.wechat.WechatRole;
import com.ruoyi.common.core.domain.entity.wechat.WechatUser;
import com.ruoyi.common.core.domain.entity.wechat.WechatUserPost;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.user.UserException;
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.domain.wechat.request.vo.*;
import com.ruoyi.system.domain.wechat.response.DeptVO;
import com.ruoyi.system.domain.wechat.response.PostVO;
import com.ruoyi.system.domain.wechat.response.WechatUserInfoVO;
import com.ruoyi.system.domain.wechat.response.WechatUserListVO;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysPostMapper;
import com.ruoyi.system.mapper.wechat.WechatRoleMapper;
import com.ruoyi.system.mapper.wechat.WechatUserMapper;
import com.ruoyi.system.mapper.wechat.WechatUserPostMapper;
import com.ruoyi.system.service.wechat.IWechatPostService;
import com.ruoyi.system.service.wechat.IWechatUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 微信小程序用户
 *
 * @author jiexiang.sun/Jason
 * @version 1.0.0
 * @create 2022-03-03 20:41
 **/
@Service
@Slf4j
public class WechatUserServiceImpl extends ServiceImpl<WechatUserMapper, WechatUser> implements IWechatUserService {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IWechatPostService wechatPostService;

    @Autowired
    private WechatUserMapper wechatUserMapper;

    @Autowired
    private WechatRoleMapper wechatRoleMapper;

    @Autowired
    private WechatUserPostMapper userPostMapper;

    @Autowired
    private SysPostMapper sysPostMapper;

    @Autowired
    private SysDeptMapper deptMapper;

    @Override
    public List<WechatUserListVO> list(FilterForWechatUserListVO params) {
        return wechatUserMapper.selectListByFilterParams(params);
    }

    @Override
    public WechatUserInfoVO info(Long userId) {
        LambdaQueryWrapper<WechatUser> wechatUserQW = new LambdaQueryWrapper<>();
        wechatUserQW.eq(WechatUser::getUserId, userId)
                .eq(WechatUser::getDelFlag, UserStatus.OK.getCode());
        WechatUser wechatUser = getOne(wechatUserQW);
        if (ObjectUtil.isEmpty(wechatUser)) {
            throw new UserException("wechat.user.not.exist", null);
        }

        WechatUserInfoVO result = new WechatUserInfoVO();
        BeanUtil.copyProperties(wechatUser, result);

        List<SysPost> wechatPosts = getPostByUserId(userId);
        if (CollectionUtil.isNotEmpty(wechatPosts)) {
            List<PostVO> postVOs = wechatPosts.stream().map(p -> {
                return new PostVO(p.getPostId(), p.getPostName());
            }).collect(Collectors.toList());

            result.setPosts(postVOs);
            result.setPostIds(postVOs.stream().map(PostVO::getPostId).collect(Collectors.toList()));
        }


        SysDept sysDept = deptMapper.selectById(wechatUser.getDeptId());
        if (ObjectUtil.isNotEmpty(sysDept)) {
            result.setDepts(new DeptVO(sysDept.getDeptId(), sysDept.getDeptName()));
        }

        WechatRole role = wechatRoleMapper.selectById(result.getRoleId());
        if (ObjectUtil.isNotNull(role)) {
            result.setRoleCode(role.getRoleKey());
        }

        return result;
    }

    /**
     * 添加用户
     *
     * @param params
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean create(CreateForWechatUserVO params) {
        //检查手机号是否已经被注册（忽略逻辑删除数据）
        LambdaQueryWrapper<WechatUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(WechatUser::getPhonenumber, params.getPhonenumber())
                .eq(WechatUser::getDelFlag, UserStatus.OK.getCode());
        if (count(lambdaQueryWrapper) > 0) {
            throw new UserException("wechat.mobile.number.is.already.registered", null);
        }

        //检查岗位是否存在
        List<SysPost> sysPosts = sysPostMapper.selectPostAll();
        if (CollectionUtil.isEmpty(sysPosts)) {
            log.error("用户注册失败，原因：系统还没有微信小程序岗位数据，请先添加岗位，注册用户手机号码：{}", params.getPhonenumber());
            return false;
        }

        /**
         * 过滤请求参数中的岗位，剔除不存在的岗位编号
         */
        Set<Long> postIdSet = sysPosts.stream().map(SysPost::getPostId).collect(Collectors.toSet());
        List<Long> effectivePostIds = params.getPostIds().stream().filter(postId -> postIdSet.contains(postId)).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(effectivePostIds)) {
            log.error("添加用户失败，原因：系统中不存在请求参数中的岗位信息，用户手机号码：{}，请求参数岗位id:{}", params.getPhonenumber(), params.getPostIds());
            throw new UserException("wechat.user.register.post.not.exist.db", null);
        }

        WechatUser wechatUser = new WechatUser();
        BeanUtil.copyProperties(params, wechatUser);
        wechatUser.setUserId(IdUtil.getSnowflakeNextId());
        wechatUser.setPassword(SecureUtil.md5((StrUtil.isBlank(params.getPassword()) ? redisCache.getCacheObject(Constants.SYS_CONFIG_KEY + "sys.user.initPassword") : params.getPassword())));
        save(wechatUser);

        effectivePostIds.forEach(postId -> {
            userPostMapper.insert(new WechatUserPost(wechatUser.getUserId(), postId));
        });

        return true;
    }

    /**
     * 修改用户
     *
     * @param params
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean modify(ModifyForWechatUserVO params) {
        LambdaQueryWrapper<WechatUser> wechatUserQW = new LambdaQueryWrapper<>();
        wechatUserQW.eq(WechatUser::getUserId, params.getUserId())
                .eq(WechatUser::getDelFlag, UserStatus.OK.getCode());
        WechatUser wechatUser = getOne(wechatUserQW);
        if (ObjectUtil.isEmpty(wechatUser)) {
            throw new UserException("wechat.user.not.exist", null);
        }

        //检查手机号是否已经被注册（忽略逻辑删除数据）
        LambdaQueryWrapper<WechatUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(WechatUser::getPhonenumber, params.getPhonenumber())
                .eq(WechatUser::getDelFlag, UserStatus.OK.getCode());
        WechatUser user = getOne(lambdaQueryWrapper);
        if (ObjectUtil.isNotNull(user) && !user.getUserId().equals(params.getUserId())) {
            throw new UserException("wechat.mobile.number.is.already.registered", null);
        }

        wechatUser = new WechatUser();
        BeanUtil.copyProperties(params, wechatUser);
        updateById(wechatUser);

        LambdaUpdateWrapper<WechatUserPost> userPostUW = new LambdaUpdateWrapper<>();
        userPostUW.eq(WechatUserPost::getUserId, wechatUser.getUserId());
        userPostMapper.delete(userPostUW);
        params.getPostIds().forEach(postId -> {
            userPostMapper.insert(new WechatUserPost(params.getUserId(), postId));
        });

        return true;
    }

    /**
     * 账号注册
     *
     * @param params
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean register(WechatUserRegisterVO params) {
        //检查验证码正确性
        String code = redisCache.getCacheObject(WechatConstants.WECHAT_ACCOUNT_REGISTER_CAPTCHA_CACHE_KEY_PREFIX + params.getPhonenumber());
        if (StrUtil.isBlank(code)) {
            log.info("缓存中没有找到该手机号码【{}】的验证码信息，可能已经过期或者没有生成过，完整的KEY：【{}】", params.getPhonenumber(), WechatConstants.WECHAT_ACCOUNT_REGISTER_CAPTCHA_CACHE_KEY_PREFIX + params.getPhonenumber());
            throw new UserException("wechat.user.register.captcha.is.error", null);
        }

        if (!StrUtil.equals(code, params.getCaptcha())) {
            throw new UserException("wechat.user.register.captcha.is.error", null);
        }

        //清空缓存验证码
        redisCache.deleteObject(WechatConstants.WECHAT_ACCOUNT_REGISTER_CAPTCHA_CACHE_KEY_PREFIX + params.getPhonenumber());

        //检查手机号是否已经被注册（忽略逻辑删除数据）
        LambdaQueryWrapper<WechatUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(WechatUser::getPhonenumber, params.getPhonenumber())
                .eq(WechatUser::getDelFlag, UserStatus.OK.getCode());
        if (count(lambdaQueryWrapper) > 0) {
            throw new UserException("wechat.mobile.number.is.already.registered", null);
        }

        //检查岗位是否存在
        List<SysPost> sysPosts = sysPostMapper.selectPostAll();
        if (CollectionUtil.isEmpty(sysPosts)) {
            log.error("用户注册失败，原因：系统还没有微信小程序岗位数据，请先添加岗位，注册用户手机号码：{}", params.getPhonenumber());
            return false;
        }

        /**
         * 过滤请求参数中的岗位，剔除不存在的岗位编号
         */
        Set<Long> postIdSet = sysPosts.stream().map(SysPost::getPostId).collect(Collectors.toSet());
        List<Long> effectivePostIds = params.getPostIds().stream().filter(postId -> postIdSet.contains(postId)).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(effectivePostIds)) {
            log.error("用户注册失败，原因：系统中不存在请求参数中的岗位信息，注册用户手机号码：{}，请求参数岗位id:{}", params.getPhonenumber(), params.getPostIds());
            throw new UserException("wechat.user.register.post.not.exist.db", null);
        }

        WechatUser wechatUser = new WechatUser();
        wechatUser.setUserId(IdUtil.getSnowflakeNextId());
        wechatUser.setPhonenumber(params.getPhonenumber());
        wechatUser.setPassword(SecureUtil.md5(params.getPassword()));
        save(wechatUser);

        effectivePostIds.forEach(postId -> {
            userPostMapper.insert(new WechatUserPost(wechatUser.getUserId(), postId));
        });

        return true;
    }


    /**
     * 账号密码找回
     *
     * @param params
     * @return
     */
    @Override
    public boolean modifyPassword(WechatUserForgetPasswordVO params) {
        //检查验证码正确性
        String code = redisCache.getCacheObject(WechatConstants.WECHAT_ACCOUNT_FORGET_PASSWORD_CAPTCHA_CACHE_KEY_PREFIX + params.getPhonenumber());
        if (StrUtil.isBlank(code)) {
            log.info("缓存中没有找到该手机号码【{}】的验证码信息，可能已经过期或者没有生成过，完整的KEY：【{}】", params.getPhonenumber(), WechatConstants.WECHAT_ACCOUNT_REGISTER_CAPTCHA_CACHE_KEY_PREFIX + params.getPhonenumber());
            throw new UserException("wechat.user.register.captcha.is.error", null);
        }

        if (!StrUtil.equals(code, params.getCaptcha())) {
            throw new UserException("wechat.user.register.captcha.is.error", null);
        }

        //清空缓存验证码
        redisCache.deleteObject(WechatConstants.WECHAT_ACCOUNT_FORGET_PASSWORD_CAPTCHA_CACHE_KEY_PREFIX + params.getPhonenumber());

        if (!StrUtil.equals(params.getPassword(), params.getConfirmPassword())) {
            throw new UserException("wechat.user.two.passwords.not.match", null);
        }

        WechatUser wechatUser = new WechatUser();
        wechatUser.setPassword(SecureUtil.md5(params.getPassword()));

        LambdaUpdateWrapper<WechatUser> userUW = new LambdaUpdateWrapper<>();
        userUW.eq(WechatUser::getPhonenumber, params.getPhonenumber())
                .eq(WechatUser::getDelFlag, UserStatus.OK.getCode());

        saveOrUpdate(wechatUser, userUW);

        return true;
    }

    @Override
    public boolean audit(ModifyForWechatUserVO param) {
        LambdaUpdateWrapper<WechatUser> userUW = new LambdaUpdateWrapper<>();
        userUW.eq(WechatUser::getUserId, param.getUserId());

        WechatUser user = new WechatUser();
        user.setStatus(param.getStatus());
        user.setRoleId(param.getRoleId());
        update(user, userUW);
        return true;
    }

    @Override
    public boolean remove(Long[] userIds) {
        LambdaUpdateWrapper<WechatUser> userUW = new LambdaUpdateWrapper<>();
        userUW.in(WechatUser::getUserId, userIds);

        WechatUser user = new WechatUser();
        user.setDelFlag(UserStatus.DELETED.getCode());
        user.setDeleteAudit(UserStatus.OK.getCode());
        update(user, userUW);
        return true;
    }

    @Override
    public boolean rejectDelete(Long userId) {
        LambdaUpdateWrapper<WechatUser> userUW = new LambdaUpdateWrapper<>();
        userUW.eq(WechatUser::getUserId, userId);

        WechatUser user = new WechatUser();
        user.setDeleteAudit(UserStatus.OK.getCode());
        update(user, userUW);
        return true;
    }

    @Override
    public boolean applyDelete(Long userId) {
        LambdaUpdateWrapper<WechatUser> userUW = new LambdaUpdateWrapper<>();
        userUW.eq(WechatUser::getUserId, userId);

        WechatUser user = new WechatUser();
        user.setDeleteAudit(UserStatus.DELETED.getCode());
        update(user, userUW);
        return true;
    }

    private List<SysPost> getPostByUserId(Long userId) {
        LambdaQueryWrapper<WechatUserPost> wechatUserPostWQ = new LambdaQueryWrapper<>();
        wechatUserPostWQ.eq(WechatUserPost::getUserId, userId);
        List<WechatUserPost> wechatUserPosts = userPostMapper.selectList(wechatUserPostWQ);

        if (CollectionUtil.isEmpty(wechatUserPosts)) {
            return Collections.EMPTY_LIST;
        }

        LambdaQueryWrapper<SysPost> wechatPostLambdaQW = new LambdaQueryWrapper<>();
        wechatPostLambdaQW.in(SysPost::getPostId, wechatUserPosts.stream().map(WechatUserPost::getPostId).collect(Collectors.toList()))
                .orderByAsc(SysPost::getPostSort);

        return sysPostMapper.selectList(wechatPostLambdaQW);
    }
}
